#include"log.hpp"
#include"threadpool.hpp"
#include"daemon.hpp"

#include<iostream>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<pthread.h>
#include<stdlib.h>
#include<signal.h>
#include<arpa/inet.h>
#include<string.h>


using namespace std;


class tcp;
class threadData
{
public:
    string clientip_;
    uint16_t clientport_;
    int sockfd_;
    tcp* ts_;
public:
    threadData(string clientip,uint16_t clientport,int sockfd,tcp* ts):clientip_(clientip),
    clientport_(clientport),sockfd_(sockfd),ts_(ts)
    {

    }

};


void service(int servicefd,string clientip,uint16_t clientport)
{
    // 2.1、获取客户发送的数据
    // 数据流使用write和read
    while (true)
    {
        char buffer[1024];
        ssize_t s = read(servicefd, buffer, sizeof(buffer)-1);
        if (s > 0)
        {
            buffer[s]=0;
            if(strcasecmp(buffer,"quit")==0)
            {
                LogMessage(DEBUG,"service[%s][%d]:quit1",clientip.c_str(),clientport);
                break;
            }
            LogMessage(NOTICE,"service[%s][%d]:transbefor:%s",clientip.c_str(),clientport,buffer);
            for(int i=0;i<s;i++)
            {
                if(isalpha(buffer[i])&&islower(buffer[i]))
                {
                    buffer[i]=toupper(buffer[i]);
                }
            }
            LogMessage(NOTICE,"service[%s][%d]:transafter:%s",clientip.c_str(),clientport,buffer);
            write(servicefd,buffer,strlen(buffer));
            //全双工通信

        }
        else if(s==0)
        {
            //写端关闭
            LogMessage(DEBUG,"service[%s][%d]:quit2",clientip.c_str(),clientport);
            break;
        }
        else
        {
            LogMessage(FATAL, "read:%s:%d", strerror(errno), servicefd);
            break;
        }
        
    }
    close(servicefd);
    LogMessage(DEBUG,"service finish[%s][%d]",clientip.c_str(),clientport);
}

void execCommand(int servicefd,string clientip,uint16_t clientport)
{
    char command[1024];
    while (true)
    {

        ssize_t s = read(servicefd, command, sizeof(command) - 1);
        if (s > 0)
        {
            command[s] = 0;
            FILE* out=popen(command,"r");
            if(out==nullptr)
            {
                LogMessage(WARNING,"execCommand[%s][%d]:popen failed",clientip.c_str(),clientport);
                break;
            }
            char work[1024]={0};
            while (fgets(work, sizeof(work) - 1, out) != nullptr)
            {
                write(servicefd, work, strlen(work));
            }
            pclose(out);
            LogMessage(DEBUG, "[%s:%d] exec [%s] ... done", clientip.c_str(), clientport, command);
            // 全双工通信
        }
        else if (s == 0)
        {
            // 写端关闭
            LogMessage(DEBUG, "execCommand[%s][%d]:quit2", clientip.c_str(), clientport);
            break;
        }
        else
        {
            LogMessage(FATAL, "read:%s:%d", strerror(errno), servicefd);
            break;
        }
    }
    close(servicefd);
    LogMessage(DEBUG, "execCommand finish[%s][%d]", clientip.c_str(), clientport);
}

class tcp
{
public:
    tcp(uint16_t port,string ip="",int sockfd=-1):ip_(ip),port_(port),threadpool_(nullptr)
    {

    }
    ~tcp()
    {

    }

    //4、多线程版本
    // static void* Routine(void* argv)
    // {
    //     threadData* client=(threadData*)argv;
    //     pthread_detach(pthread_self());
    //     service(client->sockfd_,client->clientip_,client->clientport_);
    //     delete(client);
    //     return nullptr;

    // }

    void init()
    {
        //1 创建服务器端
        listensockfd_=socket(AF_INET,SOCK_STREAM,0);
        if(listensockfd_==-1)
        {
            LogMessage(FATAL,"socket:%s:%d",strerror(errno),listensockfd_);
            exit(1);
        }
        else
        {
            LogMessage(NOTICE,"socket success:%d",listensockfd_);
        }
        //2 绑定网络信息
        //2.1 填充网络信息
        struct sockaddr_in local;
        local.sin_family=AF_INET;
        local.sin_port=htons(port_);
        local.sin_addr.s_addr=ip_.empty()?htons(INADDR_ANY):inet_addr(ip_.c_str());
        //2.2 bindsockaddr_in和套接字绑定
        if(bind(listensockfd_,(const sockaddr*)&local,(socklen_t)sizeof(local))==-1)
        {
            LogMessage(FATAL,"bind:%s:%d",strerror(errno),listensockfd_);
            exit(2);
        }
        LogMessage(DEBUG,"bind success:%d",listensockfd_);
        //3 将socket设置监听状态，因为tcp是面向连接的（面向连接：需要先建立连接，再进行工作）
        if(listen(listensockfd_,5)==-1)
        {
            LogMessage(FATAL,"listen:%s:%d",strerror(errno),listensockfd_);
            exit(3);
        }
        //设置监听状态后，允许别人来连接你
        LogMessage(DEBUG,"listen success:%d",listensockfd_);
        //加载线程池
        threadpool_=tcp::threadpool_->getinstance();
    }
    void loop()
    {
        //5、线程池先创建多个线程
        threadpool_->start();
        LogMessage(DEBUG, "thread pool start success, thread num: %d", threadpool_->thread_num());
        //signal(SIGCHLD, SIG_IGN);
        while(true)
        {
            // 1、获取连接，accept的返回值是一个新的sockfd
            // 传入的参数sockfd，这个套接字是用来获取新的连接（客户端来连接）
            // 返回值sockfd，这个套接字主要是为客户提供网络服务
            struct sockaddr_in peer;
            socklen_t len=sizeof(peer);
            int servicefd_ = accept(listensockfd_,(struct sockaddr*)&peer,&len);
            if(servicefd_==-1)
            {
                LogMessage(WARNING,"accept:%s:%d",strerror(errno),listensockfd_);
                exit(1);
            }
            LogMessage(NOTICE,"accept success:%d",listensockfd_);

            //2、进行服务
            //提取clientip和port
            uint16_t clientport=ntohs(peer.sin_port);
            string clientip=inet_ntoa(peer.sin_addr);
            //1、单进程版
            //service(servicefd_,clientip,clientport);
            //2、多进程版
            //父进程获取连接，子进程提供服务
            //不能使用waitpid，因为父进程调用waitpid时，子进程可能还没有退出，父进程就阻塞住了
            // int pid = fork();
            // if(pid==0)
            // {
            //     close(listensockfd_);
            //     service(servicefd_,clientip,clientport);
            //     exit(0);
            // }
            // close(servicefd_);

            //3、多进程版本
            //爷爷进程获取连接，孙子进程提供服务，等待父进程，孙子进程被1号进程领养，自动等待
            // int pid = fork();
            // if(pid==0)//爸爸进程
            // {
            //     int id = fork();
            //     if(id==0)    //孙子进程
            //     {
            //         close(listensockfd_);
            //         service(servicefd_,clientip,clientport);
            //         exit(0);
            //     }
            //     else
            //     {
            //         exit(0);
            //     }
            // }
            // close(servicefd_);
            //文件描述符泄露
            // //孙子进程被bash收养，退出后，由系统自动回收，不会影响其他进程
            // //爷爷进程调用waitpid时，爸爸进程肯定已经退出了，爷爷进程不会阻塞等待
            // waitpid(pid,nullptr,0);

            //4、多线程版本
            //主线程获取链接，其余线程提供服务
            // threadData* client=new threadData(clientip,clientport,servicefd_,this);
            // pthread_t tid;
            // pthread_create(&tid,nullptr,Routine,(void*)client);
            //5、线程池版本
            //先创建多个线程，主线程获取获取连接，客户端发送数据，主线程将任务放入线程池中，线程池中多个线程排队执行任务
            //线程池中的多个线程是执行任务的，不是客户端数量
            //客户端发送连接，服务器获取链接，生产任务
            
            //线程池需要把任务push进线程池中去，线程池中的线程执行任务
            // Task ts(servicefd_,clientip,clientport,service);
            // threadpool_->push(ts);
            //5、线程池版本，命令行执行结果服务
            Task ts(servicefd_,clientip,clientport,execCommand);
            threadpool_->push(ts);

        }
    }
private:
    int listensockfd_;
    uint16_t port_;
    string ip_;
    threadpool<Task> *threadpool_;

};


int main(int argc,char* argv[])
{
    cout<<"hello"<<endl;
    if(argc!=2&&argc!=3)
    {
        cout<<"failed"<<endl;
        exit(3);
    }
    string ip;
    if(argc==3)
    {
        ip=argv[2];
    }
    uint16_t port=atoi(argv[1]);
    daemon();
    tcp svr(port,ip);
    svr.init();
    svr.loop();
    return 0;
}